const sql = require('mssql');
const { conStr } = require("./config");
const fs = require("fs-extra");
const path = require("path");
const { createControl, createServices, createPageIndex, createPageAdd, createPageEdit } = require("./template/index");
var Mock = require('mockjs');
const rule = require("./template/rule");
const { Transaction } = require("./help/sqlhelp")

//获取表详情
const getTable = async (tableName) => {
  const con = await sql.connect(conStr).catch(err => {
    console.log("错误", err);
  });
  if (con == undefined) {
    return null
  }
  const sqlstr = `
  select 
  sys.columns.name, 
  sys.types.name as typeName, 
  sys.columns.max_length as typeLength, 
  sys.columns.scale as scale,
  sys.columns.is_nullable as isNullable, 
  (select count(*) from sys.identity_columns where sys.identity_columns.object_id = sys.columns.object_id and sys.columns.column_id = sys.identity_columns.column_id) as  isPK ,
  (select value from sys.extended_properties where sys.extended_properties.major_id = sys.columns.object_id and sys.extended_properties.minor_id = sys.columns.column_id) as description
  from sys.columns, sys.tables, sys.types where sys.columns.object_id = sys.tables.object_id and sys.columns.system_type_id=sys.types.system_type_id and sys.tables.name='${tableName}' order by sys.columns.column_id
  `
  const result = (await sql.query(sqlstr)).recordset;
  con.close();
  return result;
}
const getDb = async function () {
  const con = await sql.connect(conStr).catch(err => {
    console.log("错误", err);
  });
  if (con == undefined) {
    return null
  }
  const sqlstr = `
  select
  name,
  crdate
  from sysobjects where xtype='U'
  order by crdate desc
  `
  const result = (await sql.query(sqlstr)).recordset;
  con.close();
  return result;
}
//检查control文件是否存在
const checkFile = (projectName) => {
  return fs.existsSync(path.join(__dirname, `../iver/Controllers/${projectName}Controller.cs`));
}
const Save = async ({
  projectName,
  table,
  tableName,
  method = ["List", "ListByQuery", "Add", "Edit", "Del"],
  isExport = true,
  isImport = true,
  isMock = false,
  mockCount = 50,
  CName,
}) => {
  WriteCsproj(projectName);
  WriteController({ projectName, table, tableName, method, isImport, })
  WriteServices({ projectName, method, table })
  WritePage({
    table,
    projectName,
    method,
    isExport,
    isImport,
  })
  WriteMenu({
    projectName,
    CName,
  })
  if (isMock) {
    await WriteMock({
      mockCount,
      table,
      tableName,
    })
  }
  return true;
}
async function WriteMock({
  table,
  mockCount,
  tableName,
}) {
  const dlist = table.filter(item => item.isPK == 0);
  const result = await Promise.all(dlist.map(item => rule[item.typeName].mock(item)));

  let obj = {};
  for (let i = 0; i < result.length; i++) {
    obj[Object.keys(result[i])[0]] = Object.values(result[i])[0];
  }
  const data = Mock.mock({
    [`myList|${mockCount}`]: [obj]
  })
  const con = await sql.connect(conStr).catch(err => {
    console.log("错误", err);
  });
  const sqlRes = await Transaction(data.myList.map(vitem => `INSERT INTO ${tableName} VALUES
  (${table
      .filter(item => item.isPK == 0)
      .map(item => `${rule[item.typeName].insertSql(vitem[item.name])}`).join(',')
    }
  )`))
  console.log(sqlRes);
  con.close();
  return true;
}
function WritePage({
  table = [],
  projectName = "",
  method = ["List", "ListByQuery", "Add", "Edit", "Del"],
  isExport = true,
  isImport = true,
}) {
  const dirName = projectName.substring(0, 1).toUpperCase() + projectName.substring(1);
  fs.ensureDirSync(path.join(__dirname, `../iver/admin/src/pages/${dirName}/components`))
  if (method.some(item => item == "Add")) {
    fs.writeFileSync(path.join(__dirname, `../iver/admin/src/pages/${dirName}/components/CreateForm.jsx`), createPageAdd());
  }
  if (method.some(item => item == "Edit")) {
    fs.writeFileSync(path.join(__dirname, `../iver/admin/src/pages/${dirName}/components/UpdateForm.jsx`), createPageEdit());
  }
  fs.writeFileSync(path.join(__dirname, `../iver/admin/src/pages/${dirName}/index.jsx`), createPageIndex({
    table,
    projectName,
    method,
    isExport,
    isImport,
  }))
  return true;
}
function WriteServices({ projectName, method, table }) {
  const fileStr = createServices({
    projectName,
    method,
    table,
  })
  const myPath = path.join(__dirname, `../iver/admin/src/services/${projectName}Service.js`);
  if (fs.existsSync(myPath)) {
    console.log(`warnning:文件"${myPath}"已存在,操作已覆盖原有文件!`)
  }
  fs.writeFileSync(myPath, fileStr);
  return true;
}
//写项目文件
function WriteCsproj(projectName) {
  const myPath = path.join(__dirname, "../iver/iver.csproj");
  let rstr = fs.readFileSync(myPath);
  const addStr = `<Compile Include="Controllers\\${projectName}Controller.cs" />`;
  if (rstr.includes(addStr)) {
    console.log(`warnning:文件夹以包含"${projectName}Controller.cs",操作已覆盖原有文件!`)
    return true;
  }
  const wstr = rstr.toString().replace(`<Compile Include="Global.asax.cs">`, `${addStr}\n\t\t<Compile Include="Global.asax.cs">`)
  fs.writeFileSync(myPath, wstr);
  return true;
}

//写controller文件
function WriteController({ projectName, table, tableName, method, isImport, }) {
  const fileStr = createControl({
    table,
    tableName,
    projectName,
    method,
    isImport,
  });
  fs.writeFileSync(path.join(__dirname, `../iver/Controllers/${projectName}Controller.cs`), fileStr);
  return true;
}

function WriteMenu({
  projectName,
  CName,
}) {
  const menu = JSON.parse(fs.readFileSync(path.join(__dirname, `../iver/admin/config/menu.json`)).toString());
  const UprojectName = projectName.substring(0, 1).toUpperCase() + projectName.substring(1);
  //判断menu菜单是否有英文名不同的节点
  if (!menu.some(item => item.path.toLowerCase() == "/" + projectName.toLowerCase())) {
    menu.push({
      "name": CName ? CName : projectName,
      "icon": "smile",
      "path": "/" + projectName,
      "component": "./" + UprojectName
    });
    fs.writeFileSync(path.join(__dirname, "../iver/admin/config/menu.json"), JSON.stringify(menu, null, 2));
  }
  else {
    const m = menu.map(item => {
      return item.path.toLowerCase() != ("/" + projectName.toLowerCase()) ? item : {
        ...item,
        "name": CName ? CName : projectName,
        "component": "./" + UprojectName
      }
    })

    fs.writeFileSync(path.join(__dirname, "../iver/admin/config/menu.json"), JSON.stringify(m, null, 2));
  }
}
module.exports = {
  getTable,
  getDb,
  checkFile,
  Save,
}